﻿namespace LambdaCalc.Parser.Tests

open System
open NUnit.Framework

open LambdaCalc

[<TestFixture>]
type ``test parser-AST to lambda calc - AST conversion``() = 

    let emptyEnv = { new Parser.IParserEnvironment with
                        member i.LoadExpression(_) = Core.Atom "n0"
                        member i.StoreExpression(_,_) = ()
                        member i.KnownIdentifiers = Seq.empty
                        member i.CoreParameters = Core.SystemParameters.Default
                   }
    let translate = Parser.LambdaParser.translate emptyEnv

    [<Test>]
    member test.``a Atom is translated into a Atom``() =
        let input = Parser.Atom "a"
        let expectedOutput = Core.Atom "a"
        let parserResult = translate input
        Assert.AreEqual(expectedOutput, parserResult)

    [<Test>]
    member test.``abstraction with one argument is translated into the same``() =
        let input = Parser.Abstraction (["x"], Parser.Atom "x")
        let expectedOutput = Core.Abstraction ("x", Core.Atom "x")
        let parserResult = translate input
        Assert.AreEqual(expectedOutput, parserResult)

    [<Test>]
    member test.``abstraction with multiple arguments is translated into the curried form``() =
        let input = Parser.Abstraction (["x"; "y"], Parser.Atom "x")
        let expectedOutput = Core.Abstraction ("x", Core.Abstraction("y", Core.Atom "x"))
        let parserResult = translate input
        Assert.AreEqual(expectedOutput, parserResult)

    [<Test>]
    member test.``application with two arguments is translated into an application``() =
        let input = Parser.Application ([Parser.Atom "x"; Parser.Atom "y"])
        let expectedOutput = Core.Application (Core.Atom "x", Core.Atom("y"))
        let parserResult = translate input
        Assert.AreEqual(expectedOutput, parserResult)

    [<Test>]
    member test.``application is translated left-assoziative``() =
        let input = Parser.Application [Parser.Atom "x"; Parser.Atom "y"; Parser.Atom "z"]
        let expectedOutput = Core.Application(
                                Core.Application(Core.Atom "x", Core.Atom "y"),
                                Core.Atom "z")
        let parserResult = translate input
        Assert.AreEqual(expectedOutput, parserResult)

    [<Test>]
    member test.``abcd is translated as ((ab)c)d``() =
        let input = Parser.Application [Parser.Atom "a"; Parser.Atom "b"; Parser.Atom "c"; Parser.Atom "d"]
        let expectedOutput = Core.Application(
                                Core.Application(
                                    Core.Application(Core.Atom "a", Core.Atom "b"),
                                    Core.Atom "c"),
                                Core.Atom "d")
        let parserResult = translate input
        Assert.AreEqual(expectedOutput, parserResult)
        